﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Text;
using System.Threading.Tasks;
using System.Transactions;
using Microsoft.Practices.Unity;
using Wyn.PMS.Common.SecurityControl;
using Wyn.PMS.Common.Utils;
using Wyn.PMS.Entity.DataAccess;
using Wyn.PMS.Entity.Entities;
using Wyn.PMS.Entity.IDataAccess;

namespace Wyn.PMS.Common.NightAudit
{
    /// <summary>
    /// 过账滚房费
    /// <para>--------------------------</para>
    /// <para>@Author: cnalexi@gmail.com</para> 
    /// <para>@Create: 2012/5/15</para>  
    /// </summary>
    internal class RentRoll
    {
        private static readonly IUnityContainer container = UnityContainerService.GetContainer();

        public IDictionary<string, decimal> Roll(HotelBizDay bizDay, IEnumerable<Order> orders, IList<RoomType> roomTypes)
        {
            IAccountRepository accountRepository = container.Resolve<IAccountRepository>();
          
            IList<Account> accounts = new List<Account>();

            IDictionary<string, decimal> roomFeeSum = BuildRoomFeeContainer(roomTypes);

            string hotelId = bizDay.HotelID;

            IList<string> orderIds = orders.Select(o => o.OrderID).ToList();

            foreach(var order in orders)
            {
                //生成房租子账单
                var roomAccount = BuildRoomFee(order, bizDay);

                accounts.Add(roomAccount);

                //统计房型房费
                roomFeeSum[order.RoomTypeID] += roomAccount.Balance;

                //生成调节基金账单
                var protect = BuildProtectionFee(order, bizDay);

                if (protect != null) accounts.Add(protect);

                //生成电话费账单
                //var phone = BuildPhoneFee(order, bizDay);
                //if (phone != null) accounts.Add(phone);
            }
           
            if(bizDay.Status!=EnumHelper.GetCode(NightAuditCode.Status.E)
                ||(bizDay.Status==EnumHelper.GetCode(NightAuditCode.Status.E) 
                && bizDay.Steping==(int)NightAuditCode.Steping.RentRoll) )
            {
                bizDay.Status = EnumHelper.GetCode(NightAuditCode.Status.I);

                accountRepository.BatchInsert(bizDay.HotelID, AutoCheckRoomFee.Build(accounts));

                Task.Factory.StartNew(() =>
                                          {
                                              try
                                              {
                                                SumBalanceAccountRoots(hotelId, orderIds);
                                              }catch(Exception ex)
                                              {
                                                  OperateLog.ErrorLog(ex.Message,ex);
                                              }
                                          });
            }

            return roomFeeSum;
        }

        private IDictionary<string, decimal> BuildRoomFeeContainer(IList<RoomType> roomTypes)
        {
            IDictionary<string, decimal> roomFeeContainer = new Dictionary<string, decimal>();

            foreach(var roomtype in roomTypes)
            {
                roomFeeContainer.Add(roomtype.RoomTypeID, decimal.Zero);
            }
            return roomFeeContainer;
        }

        private Account BuildRoomFee(Order order,HotelBizDay bizDay)
        {
            var price= order.PriceDetail.FirstOrDefault(p => p.BizDay == bizDay.BizDay);

            if(price==null)
            {
                price = order.PriceDetail.FirstOrDefault(p => p.BizDay == DateTime.Today) 
                    ??order.PriceDetail.FirstOrDefault();
            }
            decimal fee = 0;

            if (price != null)
            {
                fee = price.Price;
            }
            
            return BuildAccount(fee, order,bizDay, LedgerCode.标准房租,LedgerCode.客房收入);
        }

        private Account BuildProtectionFee(Order order, HotelBizDay bizDay)
        {
            if(bizDay.AdjustValue.HasValue)
            {
                var price = order.PriceDetail.FirstOrDefault(p => p.BizDay == bizDay.BizDay);
                
                decimal fee = bizDay.AdjustValue.Value;

                if (bizDay.AdjustType == GlobalConst.LEDGER_PROTECTION_TYPE_RATE)
                {
                    fee = price.Price*bizDay.AdjustValue.Value;
                }

                return BuildAccount(fee, order, bizDay, LedgerCode.政府调节基金, LedgerCode.其他收入);
            }

            return null;
        }

        private Account BuildPhoneFee(Order order, HotelBizDay bizDay)
        {
            //TODO:有电话费
            if(false)
            {
                decimal fee = 0;

                return BuildAccount(fee, order, bizDay, LedgerCode.客房电话, LedgerCode.电话收入);
            }
            return null;
        }

        private Account BuildAccount(decimal fee, Order order, HotelBizDay bizDay, string code,string parentCode)
        {
            return new Account
                       {
                           AccountRootID = order.OrderID,
                           AccountID = BillGenerator.CreateID(order.HotelID, LicenceTypeHelper.PREFIX_DEBIT),
                           ActualMoney = fee,
                           Balance = fee,
                           BizDay = bizDay.BizDay,
                           CreateOrderID = order.OrderID,
                           CreateTime = DateTime.Now,
                           EmployeeID = GlobalConst.NIGHT_AUDIT_SYSTEM,
                           HotelID = order.HotelID,
                           Status = EnumHelper.GetCode(AccountStatus.I),
                           LedgerCode = code,
                           LedgerParentCode = parentCode,
                           LedgerType = AccountType.D,
                           LatestRoomNo=order.RoomNo,
                           AccountRootType = EnumHelper.GetCode(AccountRootType.RA),
                           ModifiedTime=DateTime.Now,
                           ShiftID=GlobalConst.NIGHT_AUDIT_SHIFT,
                           CreateEmployeeId=GlobalConst.NIGHT_AUDIT_SYSTEM,
                           CheckInType=order.CheckInType,
                           Note="夜审入账"
                       };
        }

        private void SumBalanceAccountRoots(string hotelId,IList<string> orderIds)
        {
            IAccountRootRepository artRepository = container.Resolve<IAccountRootRepository>();

            try
            {
                artRepository.SumAllAccountRootsCreditDebit(hotelId, orderIds);
            }
            catch (Exception ex)
            {
                SecurityControl.OperateLog.ErrorLog(ex);
            }
        }

    }
}
